class Person {
    name: string
    age: number
    sex = '男'  // 隐式推断 为string

    constructor( name:string, age: number ){
        this.name = name
        this.age = age
    }
}
const s = new Person('张扬',11)
console.log(s.age,s.name)

class Point {
    x = 1
    y = 2

    scale(n: number){
        this.x *= n
        this.y *= n
    }
}
const point1 = new Point()
point1.scale(10)
console.log(point1.x,point1.y)

// 继承
class Animal {
    move(){
        console.log('走两步')
    }
}
class Dog extends Animal {
    bark(){
        console.log('狗叫')
    }
}
const dog = new Dog()
dog.move()
dog.bark()

// 接口
interface Singable {
    sing(): void
    name: string
}
class Singer implements Singable {
    name: string
    sing(){
        console.log('你说嘴巴嘟嘟')
    }
    constructor(name: string){
        this.name = name
    }
}
const singer = new Singer('嘟嘟姐')
console.log(singer.name)
singer.sing()

/**
 * class类可见性的修饰符
 * 1.public 任何地方可见，默认为public
 * 2.protect 仅在其声明类以及其子类中可见，而对实例不可见(即只在类内部可用，但不能用实例调用)
 * 3.private 仅在其声明类型类可见，其实例以及其子类中都不可访问(即该类本身内部辅助函数)
 */

// 只读属性 readonly,只能在构造函数里修改类的成员值
class Actor {
    readonly age: number = 18   //若没有手动指定类型，则会变成字面量类型(如const声明的常量)，类型为'18'，后续构造函数无法将number类型赋给'18'
    constructor(age: number){
        this.age = age
    } 
    setAge(age: number){    // 无法赋值
        // this.age = age
    }
}
// readonly也可以用在接口里
interface Obj {
    readonly name: string
}
let obj1: Obj = {
    name:'对象'
}
// obj1.name = '对象1'  // 只读，无法赋值
let obj2: {readonly name:string} = {
    name:'对象'
}
// obj2.name = 'object'  // 只读，无法赋值

// 类的兼容性
class Point2D {
    x: number =1
    y: number =2
}
class Point3D {
    x: number = 1
    y: number = 2
    z: number = 3
}
const point2d: Point2D = new Point3D()  // 多的可以赋给少的
// const point3d: Point3D = new Point2D()  // 少的不能赋给多的

// 接口的兼容性
interface xy {
    x: number
    y: number
}
interface xyz {
    x: number
    y: number
    z: number
}
let x1: xyz ={ x:1, y:2, z:3 }
let x2: xy = x1 // 成员多的能赋给成员少的

// 函数间的兼容性，需考虑 
// 1.参数个数 参数少的可以赋给参数多的，反之不行
type F1 = ( a: number ) => void  
type F2 = ( a: number, b: number) => void
let f1: F1 = function(temp){ console.log(temp) }
let f2: F1 = f1     //参数少的可以赋给参数多的，与类和接口的兼容性相反！！！！！！！！！！

// 2.参数类型 相同位置的参数类型要相同(原始类型)或兼容(对象类型)
type F3 = ( a: number ) => string
type F4 = ( a: number ) => string
type F5 = ( a: number, b:number ) => string
let f3: F3 = function(temp){ return 'temp' }
let f4: F4 = f3
let f5: F5 = f3

// 3.返回值类型 
/**
 * 如果返回值类型是原始类型，此时两个类型要相同
 * 如果返回值类型是对象类型，此时成员多的可以赋给成员少的
 */
type F6 = ( a: number ) => { a: number }
type F7 = ( a: number ) => { a: number, b: string }
let f7: F7 = function(temp){ return { a: temp, b: 'temp' } }
let f6: F6 = f7

// 交叉类型
interface Personal {
    name: string
}
interface Contact {
    phone: number
    qq: number
}
type PersonDetail = Personal & Contact
const obj3: PersonDetail = {name: 'zhangyang', phone: 18273451223, qq:2}  // 这样就有了Personal和Contact两个接口的属性方法

// 抽象类
/**
 * 概述：抽象类是一种无法被实例化的类，专门用来定义类的结构和行为，类中额可以写抽象方法，也可以写具体实现。
 *      抽象类主要为其派生类提供一个基础结构，要求其派生类必须实现其中的抽象方法。
 */
abstract class Package {
    // 构造方法
    constructor(public weight: number){

    }

    // 抽象方法
    abstract caculate(): number

    // 具体方法
    printPackage(){
        console.log(`包裹的重量为：${this.weight}kg,运费为：${this.caculate()}元`)
    }
}

// 继承抽象类，要实现抽象类里的所有
class StandardPackage extends Package {
    constructor(weight: number, public unitPrice: number){
        super(weight)
        this.unitPrice = unitPrice
    }
    caculate(): number {
        return this.weight * this.unitPrice
    }
}

const package1 = new StandardPackage(8,5)   // 八公斤 每公斤五元
package1.printPackage() // 仍可以调用抽象类的具体方法
// 抽象类就是在定义一种规范